<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="vEKgu" id="vEKgu"><span data-lake-id="u198c0e30" id="u198c0e30">典型回答</span></h1>
  <p data-lake-id="ub3c6399e" id="ub3c6399e"><br></p>
  <p data-lake-id="u3c2f9bea" id="u3c2f9bea"><span data-lake-id="u4f72c2c1" id="u4f72c2c1">因为如果要实现多继承，就会像C++中一样，存在</span><strong><span data-lake-id="udcfba720" id="udcfba720">菱形继承</span></strong><span data-lake-id="u8da11f7d" id="u8da11f7d">的问题，C++为了解决菱形继承问题，又引入了</span><strong><span data-lake-id="u4fcb0543" id="u4fcb0543">虚继承</span></strong><span data-lake-id="u0aa06807" id="u0aa06807">。因为支持多继承，引入了菱形继承问题，又因为要解决菱形继承问题，引入了虚继承。而经过分析，人们发现我们其实真正想要使用多继承的情况并不多。所以，在 Java 中，不允许“多继承”，即一个类不允许继承多个父类。</span></p>
  <p data-lake-id="ud3cc455b" id="ud3cc455b"><span data-lake-id="ua9ae34e9" id="ua9ae34e9">​</span><br></p>
  <p data-lake-id="u3bc698ab" id="u3bc698ab"><span data-lake-id="u960b2bf3" id="u960b2bf3">除了菱形的问题，支持多继承复杂度也会增加。一个类继承了多个父类，可能会继承大量的属性和方法，导致类的接口变得庞大、难以理解和维护。此外，在修改一个父类时，可能会影响到多个子类，增加了代码的耦合度。</span></p>
  <p data-lake-id="u839d8aaf" id="u839d8aaf"><span data-lake-id="uef186672" id="uef186672">​</span><br></p>
  <p data-lake-id="u5555d350" id="u5555d350"><span data-lake-id="ud5c97ceb" id="ud5c97ceb">在Java 8以前，接口中是不能有方法的实现的。所以一个类同时实现多个接口的话，也不会出现C++中的歧义问题。因为所有方法都没有方法体，真正的实现还是在子类中的。但是，Java 8中支持了默认函数（default method ），即接口中可以定义一个有方法体的方法了。</span></p>
  <p data-lake-id="ub775b615" id="ub775b615"><br></p>
  <p data-lake-id="u46e7b9c5" id="u46e7b9c5"><span data-lake-id="u246f15e1" id="u246f15e1">而又因为Java支持同时实现多个接口，这就相当于通过implements就可以从多个接口中继承到多个方法了，但是，Java8中为了避免菱形继承的问题，在实现的多个接口中如果有相同方法，就会要求该类必须重写这个方法。</span></p>
  <p data-lake-id="u0409391d" id="u0409391d"><span data-lake-id="uc257e433" id="uc257e433">​</span><br></p>
  <h1 data-lake-id="AKi5k" id="AKi5k"><span data-lake-id="u49aa4deb" id="u49aa4deb">扩展知识</span></h1>
  <p data-lake-id="u676f46a6" id="u676f46a6"><br></p>
  <h2 data-lake-id="rUerZ" id="rUerZ"><span data-lake-id="u04598360" id="u04598360">菱形继承问题</span></h2>
  <p data-lake-id="u7b21cded" id="u7b21cded"><span data-lake-id="u529959c3" id="u529959c3">Java的创始人James Gosling曾经回答过，他表示：</span></p>
  <p data-lake-id="u70e78107" id="u70e78107"><span data-lake-id="ub591833e" id="ub591833e">​</span><br></p>
  <p data-lake-id="udac9f82f" id="udac9f82f"><span data-lake-id="uc0d5e36e" id="uc0d5e36e">“Java之所以不支持一个类继承多个类，主要是因为在设计之初我们听取了来自C++和Objective-C等阵营的人的意见。因为多继承会产生很多歧义问题。”</span></p>
  <p data-lake-id="ubd700e0f" id="ubd700e0f"><span data-lake-id="ubeb4c442" id="ubeb4c442">​</span><br></p>
  <p data-lake-id="u9c1819c3" id="u9c1819c3"><span data-lake-id="ua804c2ad" id="ua804c2ad">Gosling老人家提到的歧义问题，其实是C++因为支持多继承之后带来的</span><span data-lake-id="u39f94077" id="u39f94077">菱形继承问题</span><span data-lake-id="ufb5e3469" id="ufb5e3469">。</span></p>
  <p data-lake-id="u56c72188" id="u56c72188"><span data-lake-id="u7b142782" id="u7b142782">​</span><br></p>
  <p data-lake-id="uc084ae5b" id="uc084ae5b"><span data-lake-id="u3530cbac" id="u3530cbac">假设我们有类B和类C，它们都继承了相同的类A。另外我们还有类D，类D通过多重继承机制继承了类B和类C。</span></p>
  <p data-lake-id="u5ba48cfa" id="u5ba48cfa"><img src="https://cdn.nlark.com/yuque/0/2022/jpeg/5378072/1672211742898-80096c34-a056-47fc-bf8b-0f45c4a64498.jpeg?x-oss-process=image%2Fwatermark%2Ctype_d3F5LW1pY3JvaGVp%2Csize_9%2Ctext_SmF2YSA4IEd1IFA%3D%2Ccolor_FFFFFF%2Cshadow_50%2Ct_80%2Cg_se%2Cx_10%2Cy_10"><span data-lake-id="ua6d3d6ee" id="ua6d3d6ee">​</span></p>
  <p data-lake-id="u8712e6bf" id="u8712e6bf"><span data-lake-id="uc73ab57b" id="uc73ab57b">这时候，因为D同时继承了B和C，并且B和C又同时继承了A，那么，D中就会因为多重继承，继承到两份来自A中的属性和方法。</span></p>
  <p data-lake-id="udb30a064" id="udb30a064"><span data-lake-id="u5fc6f921" id="u5fc6f921">​</span><br></p>
  <p data-lake-id="u3971f457" id="u3971f457"><span data-lake-id="uba3a9876" id="uba3a9876">这时候，在使用D的时候，如果想要调用一个定义在A中的方法时，就会出现歧义。</span></p>
  <p data-lake-id="udc06e98b" id="udc06e98b"><span data-lake-id="u658595b1" id="u658595b1">​</span><br></p>
  <p data-lake-id="ue24a5088" id="ue24a5088"><span data-lake-id="u16456dbf" id="u16456dbf">因为这样的继承关系的形状类似于菱形，因此这个问题被形象地称为菱形继承问题。</span></p>
  <p data-lake-id="u9d0ebfcc" id="u9d0ebfcc"><span data-lake-id="u0af1d827" id="u0af1d827">​</span><br></p>
  <p data-lake-id="u81b6c002" id="u81b6c002"><span data-lake-id="ufae459e5" id="ufae459e5">而C++为了解决菱形继承问题，又引入了</span><strong><span data-lake-id="u2a583e77" id="u2a583e77">虚继承</span></strong><span data-lake-id="u1f843b48" id="u1f843b48">。</span></p>
  <p data-lake-id="uf0a38f21" id="uf0a38f21"><span data-lake-id="u82d9a47a" id="u82d9a47a">​</span><br></p>
  <p data-lake-id="u2dcbbd57" id="u2dcbbd57"><span data-lake-id="u026b7f16" id="u026b7f16">因为支持多继承，引入了菱形继承问题，又因为要解决菱形继承问题，引入了虚继承。而经过分析，人们发现我们其实真正想要使用多继承的情况并不多。</span></p>
  <p data-lake-id="ue1848ba6" id="ue1848ba6"><span data-lake-id="u5c70ed96" id="u5c70ed96">​</span><br></p>
  <p data-lake-id="u1915542f" id="u1915542f"><span data-lake-id="u2e349ab1" id="u2e349ab1">所以，在 Java 中，不允许“声明多继承”，即一个类不允许继承多个父类。但是 Java 允许“实现多继承”，即一个类可以实现多个接口，一个接口也可以继承多个父接口。由于接口只允许有方法声明而不允许有方法实现（Java 8之前），这就避免了 C++ 中多继承的歧义问题。</span></p>
  <p data-lake-id="u99cd9905" id="u99cd9905"><span data-lake-id="u1cf6255b" id="u1cf6255b">​</span><br></p>
  <h2 data-lake-id="CA6U5" id="CA6U5"><span data-lake-id="u30fcd0df" id="u30fcd0df">Java 8中的多继承</span></h2>
  <p data-lake-id="u177ca311" id="u177ca311"><br></p>
  <p data-lake-id="u883bc5f1" id="u883bc5f1"><span data-lake-id="u767e41aa" id="u767e41aa">Java不支持多继承，但是是支持多实现的，也就是说，同一个类可以同时实现多个接口。</span></p>
  <p data-lake-id="u6c43b6f8" id="u6c43b6f8"><span data-lake-id="uab7473b1" id="uab7473b1">​</span><br></p>
  <p data-lake-id="u53220d2d" id="u53220d2d"><span data-lake-id="uebea60da" id="uebea60da">我们知道，在Java 8以前，接口中是不能有方法的实现的。所以一个类同时实现多个接口的话，也不会出现C++中的歧义问题。因为所有方法都没有方法体，真正的实现还是在子类中的。</span></p>
  <p data-lake-id="u1287fd0f" id="u1287fd0f"><span data-lake-id="u2aedd5a4" id="u2aedd5a4">​</span><br></p>
  <p data-lake-id="u44d5a2a9" id="u44d5a2a9"><span data-lake-id="u395295e1" id="u395295e1">那么问题来了。</span></p>
  <p data-lake-id="ucc6dcf02" id="ucc6dcf02"><span data-lake-id="u24c703ff" id="u24c703ff">​</span><br></p>
  <p data-lake-id="u8cef487b" id="u8cef487b"><span data-lake-id="u130362ef" id="u130362ef">Java 8中支持了默认函数（default method ），即接口中可以定义一个有方法体的方法了。</span></p>
  <p data-lake-id="uf5dfd77d" id="uf5dfd77d"><span data-lake-id="ube543aab" id="ube543aab">​</span><br></p>
  <pre lang="java"><code>
public interface Pet {

    public default void eat(){
        System.out.println("Pet Is Eating");
    }
}
</code></pre>
  <p data-lake-id="ud4c4af9a" id="ud4c4af9a"><span data-lake-id="ud4eac02c" id="ud4eac02c">​</span><br></p>
  <p data-lake-id="u84c3c4f4" id="u84c3c4f4"><span data-lake-id="u6ae9ebb6" id="u6ae9ebb6">而又因为Java支持同时实现多个接口，这就相当于通过implements就可以从多个接口中继承到多个方法了，这不就是变相支持了多继承么。</span></p>
  <p data-lake-id="uee8a91cd" id="uee8a91cd"><span data-lake-id="ud51a0d2a" id="ud51a0d2a">那么，Java是怎么解决菱形继承问题的呢？我们再定义一个哺乳动物接口，也定义一个eat方法。</span></p>
  <p data-lake-id="uf708b984" id="uf708b984"><span data-lake-id="uc1dae05f" id="uc1dae05f">​</span><br></p>
  <pre lang="java"><code>
public interface Mammal {

    public default void eat(){
        System.out.println("Mammal Is Eating");
    }
}
</code></pre>
  <p data-lake-id="u2c658e4a" id="u2c658e4a"><span data-lake-id="u16ed7a77" id="u16ed7a77">​</span><br></p>
  <p data-lake-id="ufddfb911" id="ufddfb911"><span data-lake-id="ue695d304" id="ue695d304">然后定义一个Cat，让他分别实现两个接口：</span></p>
  <pre lang="java"><code>
public class Cat implements Pet,Mammal {

}
</code></pre>
  <p data-lake-id="u4612d427" id="u4612d427"><span data-lake-id="u67b38d5e" id="u67b38d5e">这时候，编译期会报错：</span></p>
  <p data-lake-id="u360f2c43" id="u360f2c43"><span data-lake-id="uf08d0328" id="uf08d0328">​</span><br></p>
  <blockquote data-lake-id="uf8f9f97d" id="uf8f9f97d">
   <p data-lake-id="uf45bc8e9" id="uf45bc8e9"><span data-lake-id="ub33aa6f7" id="ub33aa6f7">error: class Cat inherits unrelated defaults for eat() from types Mammal and Pet</span></p>
  </blockquote>
  <p data-lake-id="u92885c60" id="u92885c60"><br></p>
  <p data-lake-id="ub4c26296" id="ub4c26296"><span data-lake-id="ud0dedf34" id="ud0dedf34">这时候，就要求Cat类中，必须重写eat()方法。</span></p>
  <pre lang="java"><code>
public class Cat implements Pet,Mammal {
    @Override
    public void eat() {
        System.out.println("Cat Is Eating");
    }
}
</code></pre>
  <p data-lake-id="u99417260" id="u99417260"><span data-lake-id="u69f9ee29" id="u69f9ee29">​</span><br></p>
  <p data-lake-id="u5b52a10a" id="u5b52a10a"><span data-lake-id="ufc218aa8" id="ufc218aa8">所以可以看到，Java并没有帮我们解决多继承的歧义问题，而是把这个问题留给开发人员，通过重写方法的方式自己解决。</span></p>
 </body>
</html>